import sys
import json
import secrets
import httpx
import fastapi
from starlette.config import Config
from starlette.requests import Request
from authlib.integrations.starlette_client import OAuth
from starlette.middleware.sessions import SessionMiddleware

global auth_token

def headers(): 
    return { "Authorization": "Bearer " + auth_token.get("access_token") }

def update_token(token, refresh_token=None, access_token=None):
    if refresh_token:
        item = auth_token.find(name="cc98", refresh_token=refresh_token)
    elif access_token:
        item = auth_token.find(name="cc98", access_token=access_token)
    else:
        return
    # 更新旧令牌
    item.access_token = token['access_token']
    item.refresh_token = token.get('refresh_token')
    item.expires_at = token['expires_at']
    item.save()


oauth = OAuth(Config(".env"), update_token=update_token)
oauth.register(
    name="cc98",
    server_metadata_url="https://openid.cc98.org/.well-known/openid-configuration",
    client_kwargs={"scope": "openid cc98-api offline_access"},
)
app = fastapi.FastAPI(debug=True)
app.add_middleware(SessionMiddleware, secret_key=secrets.token_urlsafe(32))  

@app.get("/", response_class=fastapi.responses.HTMLResponse)
def read_root():
    return '<a href="/login">Login with CC98</a>'

@app.get("/login")
async def login(request: Request):
    redirect_uri = request.url_for("auth")
    return await oauth.cc98.authorize_redirect(request, redirect_uri)

@app.get("/auth")
async def auth(request: Request):
    global auth_token
    token = await oauth.cc98.authorize_access_token(request)
    request.session["token"] = token
    auth_token = token
    return token

@app.get("/top10")
async def top10():
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/config/index",
            headers=headers()
        )
        print(res)
    return { "topics": json.loads(res.text).get("hotTopic") }

@app.get("/me")
async def me():
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/me",
            headers=headers()
        )
        print(res)
    return json.loads(res.text)

@app.get("/me/follower")
async def follower(begin: int = 0, size: int = 20):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/me/follower",
            headers=headers(),
            params={ "from": begin, "size": size }
        )
        print(res)
        if (res.status_code == 401):
            return { "error": "Unauthorized" }
    return { "users": json.loads(res.text) }

@app.get("/me/followee")
async def followee(begin: int = 0, size: int = 20):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/me/followee",
            headers=headers(),
            params={ "from": begin, "size": size }
        )
        print(res)
    return { "users": json.loads(res.text) }

@app.get("/me/favorite-topic-group")
async def favorite_topic_group():
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/me/favorite-topic-group",
            headers=headers()
        )
        print(res)
    return json.loads(res.text) 

@app.get("/topic/me/favorite")
async def favorite_topic(group_id: int, begin: int = 0, size: int = 20):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/topic/me/favorite",
            headers=headers(),
            params={ "groupid": group_id, "from": begin, "size": size, "order": 0 }
        )
        print(res)
    return { "topics": json.loads(res.text) }

@app.get("/me/hot-post")
async def hot_post(begin: int = 0, size: int = 10):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/me/hot-post",
            headers=headers(),
            params={ "from": begin, "size": size }
        )
        print(res)
    return json.loads(res.text) 

@app.get("/me/recent-topic")
async def recent_topic(size: int = 5, begin: int = 0):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/me/recent-topic",
            headers=headers(),
            params={ "size": size, "from": begin }
        )
        print(res)
    return {"topics": json.loads(res.text)}

@app.get("/user/{user_id}/recent-topic")
async def user_recent_topic(user_id: int, begin: int = 0, size: int = 5):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/user/" + str(user_id) + "/recent-topic",
            headers=headers(),
            params={ "size": size, "from": begin, "userid": user_id }
        )
        print(res)
    return {"topics": json.loads(res.text)}

@app.get("/topic/new")
async def new_topic(size: int = 5, begin: int = 0):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/topic/new",
            headers=headers(),
            params={
                "size": size,
                "from": begin
            }
        )
        print(res)
    return {"topics": json.loads(res.text)}

@app.get("/Board/all")
async def all_board():
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/Board/all",
            headers=headers()
        )
        print(res)
    return {"boards": json.loads(res.text)}

@app.get("/board/{board_id}")
async def board(board_id: int):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/board/" + str(board_id),
            headers=headers()
        )
        print(res)
    return json.loads(res.text)

@app.get("/board/{board_id}/topic")
async def board_topic(board_id: int, begin: int = 0, size: int = 20):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/board/" + str(board_id) + "/topic",
            headers=headers(),
            params={ "from": begin, "size": size }
        )
        print(res)
    return {"topics": json.loads(res.text)}

@app.get("/topic/toptopics")
async def top_topics(boardid: int):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/topic/toptopics",
            headers=headers(),
            params={ "boardid": boardid }
        )
        print(res)
    return {"topics": json.loads(res.text)}

@app.get("/user/{user_id}")
async def user(user_id: int):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/user/" + str(user_id),
            headers=headers()
        )
        print(res)
    return json.loads(res.text)

@app.get("/user/name/{user_name}")
async def user_by_name(user_name: str):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/user/name/" + user_name,
            headers=headers()
        )
        print(res)
    return json.loads(res.text)

@app.get("/topic/{topic_id}")
async def topic(topic_id: int):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/topic/" + str(topic_id),
            headers=headers()
        )
        print(res)
    return json.loads(res.text)

@app.get("/Topic/{topic_id}/hot-post")
async def hot_post(topic_id: int):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/Topic/" + str(topic_id) + "/hot-post",
            headers=headers()
        )
        print(res)
    return {"posts": json.loads(res.text)}

@app.get("/topic/search")
async def search_topic(keyword: str, begin: int = 0, size: int = 20):
    async with httpx.AsyncClient() as client:
        res = await client.get(
            "https://api.cc98.org/topic/search",
            headers=headers(),
            params={ "keyword": keyword, "from": begin, "size": size }
        )
        print(res)
    return {"topics": json.loads(res.text)}

if __name__ == "__main__":
    import uvicorn
    port = 8282
    if len(sys.argv) > 1:
        port = int(sys.argv[1])
    print("Login at https://localhost:" + str(port))
    uvicorn.run(
        "main:app", 
        host="0.0.0.0", 
        port=port, 
        reload=False, 
        ssl_keyfile=".\key.pem",
        ssl_certfile=".\cert.pem"
    )
